<?php

class __admin_system_update extends Module {
	
	public function __construct () {
		parent::__construct('system');
	}
	
	public function update () {
		$this->setPageTitle (lang ('admin_header_update','system'));
		
		if (!getRequest ('start', 'bool')) {
			$response = new ModuleResponse;
			$response->setTemplate ('system/update');
			
			if (getRequest ('successfull', 'bool')) {
				$response->addObject (new SystemMessage ('Successfully updated'));
			}
			
			$regedit = Regedit::getInstance ();
	
			$response->addObject (new Array2XML ('system', array (
				'version' => $regedit->get ('//cms/version'),
				'build' => $regedit->get ('//cms/build'),
				'update' => formatDate((int) $regedit->get ('//cms/last_update'))
			)));
			
			return $response;
		}
		
		
		include ENGINE_ROOT . '/libs/pclzip.lib.php';
		
		$oTypeFileRevision = TypesController::getInstance()->getTypeByName ('file_revision');
		$objectsController = ObjectsController::getInstance ();		
		$regedit = Regedit::getInstance ();
		
		$response = new ModuleResponse;
		$response->setTemplate ('system/update');
		
		$currentBuild = (int) $regedit->get ('//cms/build');
		$version = $regedit->get ('//cms/version');

		$response->addObject (new Array2XML ('system', array (
			'version' => $version,
			'build' => $currentBuild,
			'update' => formatDate((int) $regedit->get ('//cms/last_update'))
		)));
		
		if (empty ($_FILES['zip']['tmp_name'])) {
			$response->addObject (new SystemError ('Zip archive with update not uploaded'));
			return $response;
		}
		
		$zipFilePath = DOC_ROOT . '/explay/temp/update.zip';
		
		if (!move_uploaded_file ($_FILES['zip']['tmp_name'], $zipFilePath)) {
			$response->addObject (new SystemError ('Uploading error'));
			return $response;
		}
		
		$zip = new PclZip ($zipFilePath);
		
		try {			
			$listContent = $zip->extract (PCLZIP_OPT_BY_NAME, 'update', PCLZIP_OPT_EXTRACT_AS_STRING);
			
			if (!count ($listContent)) {
				throw new BlockException ('File with update info not found');
			}
			
			$aUpdateInfo = unserialize ($listContent[0]['content']);
			
			if ((int) $aUpdateInfo['for_build'] != $currentBuild) {
				throw new BlockException ('You upload update for other build');
			}
			
			$newBuild = (int) $aUpdateInfo['build'];
			$version = $aUpdateInfo['version'];
			
			$this->unpack ($zip, $currentBuild);
			
			$listContent = $zip->extract (PCLZIP_OPT_BY_NAME, 'mysql', PCLZIP_OPT_EXTRACT_AS_STRING);
			
			if (count ($listContent)) {
				$mysqlDump = str_replace ("\r", '', $listContent[0]['content']);
				$aQueries = explode ("\n", $mysqlDump);
				
				$db = DBController::getInstance ();
				foreach ($aQueries as $query) {
					try {
						$db->query ($query);
					}
					catch (MySQLException $e) {
						continue;
					}
				}
			}
			
			$listContent = $zip->extract (PCLZIP_OPT_BY_NAME, 'php', PCLZIP_OPT_EXTRACT_AS_STRING);
			
			if (count ($listContent)) {
				$php = trim ($listContent[0]['content']);
				$php = rtrim ($php, '?>');
				
				if (substr ($php, 0, 5) == '<?php') {
					$php = substr ($php, 5);
				}
				if (substr ($php, 0, 2) == '<?') {
					$php = substr ($php, 2);
				}

				eval ($php);
			}
			
		} catch (BlockException $e) {
			$response->addObject (new SystemError ($e->getMessage ()));
			return $response;
		}
		
		$sel = new Selection;
		$sel->addType ($oTypeFileRevision);
		$sel->addFilter ('build', $currentBuild-1);
		$res = $sel->getList ();
		
		foreach ($res as $row) {
			$objectsController->getObject($oTypeFileRevision, $row[0])->delete ();
		}
		
		$regedit->set ('//cms/last_build', $currentBuild);
		$regedit->set ('//cms/build', $newBuild);
		$regedit->set ('//cms/last_update', time ());
		$regedit->set ('//cms/version', $version);
		
		if (file_exists ($zipFilePath)) {
			unlink ($zipFilePath);
		}
		
		redirect (HTTP_HOST . '/admin/system/update?successfull');
	}
	
	private function unpack (PclZip $zip, $currentBuild) {		
		$oTypeFileRevision = TypesController::getInstance()->getTypeByName ('file_revision');
		$objectsController = ObjectsController::getInstance ();
		
		$list = $zip->listContent (); // Получаем список файлов и папок
		
		if (!$list) {
			throw new BlockException ('Zip error: ' . $zip->errorInfo (true));
		}
	
		// Далее смотрим, есть ли такие файлы/папки на сервере
		foreach ($list as $item) {
			if ($item['filename'] == 'update' || $item['filename'] == 'php' || $item['filename'] == 'mysql') {
				continue;
			}
			
			$filename = DOC_ROOT . '/' . trim ($item['filename'], '/');
			
			if ($item['folder']) {
				// Если такой папки нет, то создаем ее
				if (!is_dir ($filename)) {
					mkdir ($filename);
					if (!is_writable ($filename)) {
						chmod ($filename, 0777);
					}
				}
			
			} else {
				if (file_exists ($filename)) { // Если такой файл существует, то переименовываем его и создаем запись в БД
					if (!is_writable ($filename)) {
						chmod ($filename, 0777);
					}
					
					$fileInfo = pathinfo ($filename);
					if (!rename ($filename, $fileInfo['dirname'] . '/' . '#' . $currentBuild . '_' . $fileInfo['filename'] . '.' . $fileInfo['extension'])) {
						throw new BlockException ('Can\'t rename file "' . $filename . '"');
					}
					
					$oRevision = new Object ($oTypeFileRevision);
					$oRevision->setValues (array (
						'filename' => $item['filename'],
						'build' => $currentBuild
					));
					$oRevision->createNew ();
				}
				
				// распаковываем
				$zip->extract (PCLZIP_OPT_BY_NAME, $item['stored_filename']);
			}
		}
	}
	
}